package org.smile.db.pool;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;
/**
 * Connection 的一个代理类 
 *    只是代理了 Connection的close()方法
 * @author strive
 *
 */
public class PoolConnection implements InvocationHandler{
	
	/**
	 * 要代理的方法名
	 */
	private final static String CLOSE_METHOD_NAME = "close"; 
	
    private Connection conn = null; 
    // 数据库的忙状态
    private volatile boolean isUsed = false; 
    // 用户最后一次访问该连接方法的时间
    private volatile long lastAccessTime = System.currentTimeMillis(); 
   
    PoolConnection(Connection conn, boolean isUsed){ 
        this.conn = conn; 
        this.isUsed = isUsed; 
    } 
    /** 
    * Returns the conn. 
    * @return Connection 
    */ 
    public Connection getConnection() { 
        // 返回数据库连接 conn 的接管类，以便截住 close 方法
    	Class[] interfaces=new Class[]{Connection.class};
        Object proxyConn =Proxy.newProxyInstance(conn.getClass().getClassLoader(),interfaces,this); 
        return (Connection)proxyConn; 
    } 
    /** 
    * 该方法真正的关闭了数据库的连接
    * @throws SQLException 
    */ 
    synchronized void close() throws SQLException{ 
       // 由于类属性 conn 是没有被接管的连接，因此一旦调用 close 方法后就直接关闭连接
       conn.close(); 
    } 
    /** 
    * Returns the inUse. 
    * @return boolean 
    */ 
    public synchronized boolean isUsed() { 
        return isUsed; 
    } 
    /** 
    * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, 
    * java.lang.reflect.Method, java.lang.Object) 
    */ 
    public Object invoke(Object proxy, Method m, Object[] args) 
        throws Throwable 
    { 
        Object obj = null; 
        // 判断是否调用了 close 的方法，如果调用 close 方法则把连接置为无用状态
        if(CLOSE_METHOD_NAME.equals(m.getName())) {
            setInUsed(false);
        	conn.setAutoCommit(true);
        } else {
            obj = m.invoke(conn, args);     
        }
        // 设置最后一次访问时间，以便及时清除超时的连接
        lastAccessTime = System.currentTimeMillis(); 
        return obj; 
    } 
       
    /** 
    * Returns the lastAccessTime. 
    * @return long 
    */ 
    public synchronized long getLastAccessTime() { 
        return lastAccessTime; 
    } 
    /** 
    * Sets the inUse. 
    * @param inUse The inUse to set 
    */ 
    public synchronized void setInUsed(boolean isUsed) { 
        this.isUsed = isUsed; 
    }
	

}
